package me.twoday.library.mine.common.image;

import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.URL;

import me.twoday.library.mine.common.ImageUtil;
import me.twoday.library.mine.common.image.ImageDownloaderTask.FlushedInputStream;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.widget.ImageView;

/**
 * 원격지에서 이미지를 가져오는 클래스
 * 
 * @author 박우람
 * @since 2011.02.14
 */
public class ImageDownloader
{
	public static final String TAG = "ImageDownloader";
	
	/**
	 * 이미지를 가져옵니다. 모서리 라운딩 처리는 하지 않습니다.
	 * 
	 * @param url 이미지 주소
	 * @param imageView 다운로드한 이미지를 설정할 ImageView
	 */
	public static void download(String url, ImageView imageView)
	{
		download(url, imageView, false, null);
	}
	
	/**
	 * 이미지를 가져옵니다. 모서리 라운딩 처리는 하지 않습니다.
	 * 
	 * @param url 이미지 주소
	 * @param imageView 다운로드한 이미지를 설정할 ImageView
	 * @param handler 이미지 처리 핸들러
	 */
	public static void download(String url, ImageDownloaderHandler handler)
	{
		download(url, null, false, handler);
	}
	
	/**
	 * 이미지를 가져옵니다. 모서리 라운딩 처리를 옵션으로 할 수 있습니다.
	 * 
	 * @param url 이미지 주소
	 * @param imageView 다운로드한 이미지를 설정할 ImageView
	 * @param rounded 모서리 라운드 처리 여부
	 */
	public static void download(String url, ImageView imageView, boolean rounded)
	{
		download(url, imageView, rounded, null);
	}
	
	/**
	 * 이미지를 가져옵니다. 
	 * 
	 * @param url 이미지 주소
	 * @param imageView 다운로드한 이미지를 설정할 ImageView
	 * @param rounded 모서리 라운드 처리 여부
	 * @param handler 이미지 처리 핸들러
	 */
	public static void download(String url, ImageView imageView, boolean rounded, ImageDownloaderHandler handler)
	{
		if(url == null)
		{
			return;
		}
		
		Bitmap cachedImage = ImageFileCache.getBitmapFromCache(url);
		if(cachedImage != null)
		{
			// 모서리 라운드 처리가 필요할 경우
			if(rounded)
			{
				cachedImage = ImageUtil.getRoundedCornerBitmap(cachedImage, 10);
			}
			
			imageView.setImageBitmap(cachedImage);
		}
		else if(cancelPotentialDownload(url, imageView))
		{
			// 이미지 다운로드 시작
			ImageDownloaderTask task = new ImageDownloaderTask(url, imageView, rounded);
			
			if(imageView!=null)
			{
				DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
				imageView.setImageDrawable(downloadedDrawable);
			}
			
			task.execute(url);
		}
	}
	
	/**
	 * 비동기가 아닌 동기 다운로드를 한다.
	 * 
	 * @param url 이미지가 존재하는 원격지 URL
	 * @return 다운받은 Bitmap 인스턴스
	 */
	public static Bitmap download(String url)
	{
		// 이미지가 캐시에 존재할 경우 캐시에서 이미지를 반환한다.
		Bitmap cachedImage = ImageFileCache.getBitmapFromCache(url);
		if(cachedImage != null)
		{
			return cachedImage;
		}
		// 캐시에 없을 경우 이미지를 다운로드 한다.
		else
		{
			try
			{
				URL targetUrl = new URL(url);
				HttpURLConnection connection = (HttpURLConnection) targetUrl.openConnection();
				connection.setDoInput(true);
				connection.connect();
				FlushedInputStream is = new FlushedInputStream(connection.getInputStream()); 
	
				return BitmapFactory.decodeStream(is);
			}
			catch (Exception e)
			{
				Log.e(TAG, e.getLocalizedMessage());
			}
		}
		
		return null;
	}

	private static boolean cancelPotentialDownload(String url, ImageView imageView)
	{
		ImageDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

		// 태스크가 이미 있는 경우
		if(bitmapDownloaderTask != null)
		{
			String bitmapUrl = bitmapDownloaderTask.url;
			if((bitmapUrl == null) || (!bitmapUrl.equals(url)))
			{
				bitmapDownloaderTask.cancel(true);
			}
			// 같은 이미지인 경우
			else
			{
				return false;
			}
		}
		
		// 취소할 수 있도록 한다.
		return true;
	}

	private static ImageDownloaderTask getBitmapDownloaderTask(ImageView imageView)
	{
		if(imageView != null)
		{
			Drawable drawable = imageView.getDrawable();
			if(drawable instanceof DownloadedDrawable)
			{
				DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
				return downloadedDrawable.getBitmapDownloaderTask();
			}
		}
		return null;
	}

	static class DownloadedDrawable extends ColorDrawable
	{
		private final WeakReference<ImageDownloaderTask> bitmapDownloaderTaskReference;

		public DownloadedDrawable(ImageDownloaderTask bitmapDownloaderTask)
		{
			super(Color.TRANSPARENT);
			bitmapDownloaderTaskReference = new WeakReference<ImageDownloaderTask>(bitmapDownloaderTask);
		}

		public ImageDownloaderTask getBitmapDownloaderTask()
		{
			return bitmapDownloaderTaskReference.get();
		}
	}
}
